Skip to content

Optimize export lookup and simple activation - #772

Open
Andrew Arnott (AArnott) wants to merge 4 commits into
mainfrom
perf-optimizations
Open

Optimize export lookup and simple activation#772
Andrew Arnott (AArnott) wants to merge 4 commits into
mainfrom
perf-optimizations

Conversation

@AArnott

@AArnott Andrew Arnott (AArnott) commented Aug 21, 2026

Copy link
Copy Markdown
Member

Summary

  • cache exact runtime export lookups and initialized shared root values
  • bypass general lifecycle state transitions for non-shared parts with no imports or OnImportsSatisfied callbacks
  • avoid LINQ and empty-array allocations while resolving constructor arguments through the existing reflection lifecycle
  • add BenchmarkDotNet coverage for shared, non-shared, constructor, property, complex, and ImportMany activation
  • document the investigation, JIT tradeoffs, compiled activation experiment, and staged hybrid-plan ideas in PERFORMANCE.md

This branch does not add expression-compiled constructors, setters, or activation plans. That experiment is preserved separately on perf/compiled-activation-plans and has no pull request.

Performance

Matched three-run medians from the IocPerformance scenarios. In the 1-thread variant, one thread performs 500,000 iterations. In the 2-thread variant, two threads share the same export provider and each performs 250,000 iterations concurrently. Each iteration resolves three exports, so both variants perform 1.5 million total resolutions. Values are total wall-clock time; the 2-thread variant measures concurrent throughput and contention rather than individual activation latency. main was measured at 26831df5; the PR column contains only the reduced, non-expression-compilation changes. The MEF2 control measurements differed by no more than 2.5% between runs.

Scenario main, 1 thread PR, 1 thread Speedup main, 2 threads PR, 2 threads Speedup
Singleton 7,307 ms 207 ms 35.30x 3,908 ms 124 ms 31.52x
Transient 10,367 ms 1,277 ms 8.12x 5,640 ms 866 ms 6.51x
Combined 15,656 ms 5,300 ms 2.95x 8,878 ms 3,544 ms 2.51x
Complex 40,663 ms 21,288 ms 1.91x 25,576 ms 15,419 ms 1.66x
Property 32,091 ms 21,378 ms 1.50x 17,825 ms 12,535 ms 1.42x
IEnumerable 28,558 ms 11,729 ms 2.43x 17,237 ms 8,259 ms 2.09x

The largest gains come from cached shared retrieval and the narrow lifecycle bypass for simple non-shared parts. Imported graphs retain 1.4-3.0x improvements from cached root lookup and lower constructor-argument overhead. Expression-compiled constructors, setters, and graph activation are not included in these PR results.

Validation

  • Microsoft.VisualStudio.Composition.Tests: 2,064 net8.0 and 2,107 net472 tests passed
  • benchmark project builds without warnings for net10.0 and net472
  • all six activation benchmarks execute under both target frameworks
  • no new expression compilation remains in the pull request diff

Validation pipeline

vs-mef validation build 15110883

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document the activation performance investigation and retain only the non-expression optimizations on the active PR branch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AArnott Andrew Arnott (AArnott) changed the title Improve export activation throughput Optimize export lookup and simple activation Aug 26, 2026
@AArnott
Andrew Arnott (AArnott) marked this pull request as ready for review August 28, 2026 01:11
Copilot AI lite review requested due to automatic review settings August 28, 2026 01:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR focuses on improving MEF runtime activation throughput by adding optimized fast paths for common export retrieval and simple non-shared activation, while also adding benchmarks and documentation to track and evaluate the performance work.

Changes:

  • Add an optimized GetExportedValue<T>() fast path via ExportProvider.TryGetExportedValue, and implement a runtime-provider cache for exact export lookups.
  • Add a narrow lifecycle bypass for simple non-shared parts (no imports / no OnImportsSatisfied) and remove LINQ/extra allocations in constructor argument resolution.
  • Add BenchmarkDotNet activation benchmarks and a PERFORMANCE.md write-up describing the investigation and future directions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
test/Microsoft.VisualStudio.Composition.Benchmarks/ActivationBenchmarks.cs Adds steady-state activation benchmarks for several representative activation shapes (shared, transient, complex graphs, property imports, ImportMany).
src/Microsoft.VisualStudio.Composition/RuntimeExportProviderFactory+RuntimeExportProvider.cs Implements a cached exact-export lookup fast path and reduces allocations in constructor argument resolution; adds simple non-shared lifecycle shortcut criteria.
src/Microsoft.VisualStudio.Composition/ExportProvider.cs Introduces provider-specific TryGetExportedValue hook and a non-shared direct-initialization bypass in PartLifecycleTracker.
PERFORMANCE.md Documents benchmark coverage, implemented optimizations, and future activation/JIT tradeoff ideas.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread PERFORMANCE.md Outdated
Avoid caching reentrant shared values before lifecycle finalization and make the performance documentation branch-independent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 28, 2026 01:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants